package Introspector;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.reflect.FieldUtils;


public class BeanInfoUtil {
    public static void main(String[] args) throws Exception{
        BeanInfo beanInfo=Introspector.getBeanInfo(UserInfo.class);
        PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors();
        
        UserInfo userInfo =new UserInfo();
    	Field field = userInfo.getClass().getDeclaredField("userName");
    	Class<? extends UserInfo>  cls= userInfo.getClass();
    	setProperty(userInfo,"userName");
    	long n = 400000;
    	long start=System.currentTimeMillis();
    	for(int i=1;i<=n;i++){
    		getProperty(userInfo,"userName");  /*      经测试，这种方法效率最慢             */
    	}
    	long end=System.currentTimeMillis();
    	 System.out.println("get PropertyDescriptor userName: "+(start - end));
    	 
//    	setPropertyByIntrospector(userInfo,"userName");
//    	getPropertyByIntrospector(userInfo,"userName");
    	
    	 
    	 /*  readDeclaredField传入"userName",不是Field,方法内部需要getDeclaredField,效率大大降低             */
     	start=System.currentTimeMillis();
    	for(int i=1;i<=n;i++){
    		FieldUtils.readDeclaredField(userInfo, "userName", true);	//传"userName"
    	}
    	end=System.currentTimeMillis();
    	System.out.println("get FieldUtils.readDeclaredField userName: "+(start - end));
    	 
    	Common.getFieldByName(cls, "userName");
     	start=System.currentTimeMillis();
    	for(int i=1;i<=n;i++){
    		field= Common.getFieldByName(cls, "userName");
    		FieldUtils.readField(field,userInfo,true);	  //缓存Field会大大提高效率,传field
    	}
    	end=System.currentTimeMillis();
    	System.out.println("FieldUtils.readField(field,userInfo,true) userName: "+(start - end));
    	
     	start=System.currentTimeMillis();
    	for(int i=1;i<=n;i++){
    		field= Common.getFieldByName(cls, "userName");
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            field.get(userInfo);						//缓存Field会大大提高效率,field.get
    	}
    	end=System.currentTimeMillis();
    	System.out.println("get field.get userName: "+(start - end));
    	

     	start=System.currentTimeMillis();
    	for(int i=1;i<=n;i++){
    		getVal(userInfo, "userName");	/*      经测试，这种方法效率最高             */
    	}
    	end=System.currentTimeMillis();
    	System.out.println("get Common.getGetterMethod.invoke userName: "+(start - end));
    	
     	start=System.currentTimeMillis();
    	for(int i=1;i<=n;i++){
    		getValTwo(userInfo, "userName");
    	}
    	end=System.currentTimeMillis();
    }
  
  	 /*     
  	  * 总结：反射效率并不高，缓存类信息会显著提高相率，可以达到20倍
  	  */  
    
  	 /* 	总结：反射效率并不高，缓存类信息会显著提高相率，可以达到20倍
  	  *     1. 架构部的Common.getGetterMethod(cls, field)虽然缓存了ClassInfo信息，
  	  * 	但是效率并不高,因为其每次要传入Field
  	  * 	而 getDeclaredField 获得Field本身效率就很低，然后还要进行getterMethod.invoke
  	  * 
  	  * 	2. field.get(target)没有getMethod.invoke(target) 效率高
  	  * 
  	  * 	3. FieldUtils.readDeclaredField(userInfo, fieldName, true)调用
  	  *		FieldUtils.readField(field,userInfo,true) 最终调用的是 field.get(target)
  	  */    
    
    public static void setProperty(UserInfo userInfo,String userName)throws Exception{
        PropertyDescriptor propDesc=new PropertyDescriptor(userName,UserInfo.class);
        Method methodSetUserName=propDesc.getWriteMethod();
        methodSetUserName.invoke(userInfo, "zhaoxiang");
        System.out.println("set userName: "+userInfo.getUserName());
    }
  
    public static void getProperty(UserInfo userInfo,String userName)throws Exception{
        PropertyDescriptor proDescriptor =new PropertyDescriptor(userName,userInfo.getClass());
        Method methodGetUserName=proDescriptor.getReadMethod();
        Object objUserName=methodGetUserName.invoke(userInfo);
//        System.out.println("get userName: "+objUserName.toString());
    }

    public static void setPropertyByIntrospector(UserInfo userInfo,String userName)throws Exception{
        BeanInfo beanInfo=Introspector.getBeanInfo(UserInfo.class);
        PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors();
        if(proDescrtptors!=null&&proDescrtptors.length>0){
            for(PropertyDescriptor propDesc:proDescrtptors){
                if(propDesc.getName().equals(userName)){
                    Method methodSetUserName=propDesc.getWriteMethod();
                    methodSetUserName.invoke(userInfo, "zhaoxiang ByIntrospector");
                    System.out.println("set userName:"+userInfo.getUserName());
                    break;
                }
            }
        }
    }
    
    public static void getPropertyByIntrospector(UserInfo userInfo,String userName)throws Exception{
        BeanInfo beanInfo=Introspector.getBeanInfo(UserInfo.class);
        PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors();
        if(proDescrtptors!=null&&proDescrtptors.length>0){
            for(PropertyDescriptor propDesc:proDescrtptors){
                if(propDesc.getName().equals(userName)){
                    Method methodGetUserName=propDesc.getReadMethod();
                    Object objUserName=methodGetUserName.invoke(userInfo);
                    System.out.println("get userName:"+objUserName.toString());
                    break;
                }
            }
        }
    }
    
	
	private static <T>  Object getVal(T vo, String column) {
		try {
			if (vo == null) {
				return null;
			}
			Method getM = Common.getGetterMethod(vo.getClass(), column);
			if(!getM.isAccessible()){
				//快速访问，不进行安全检查,据说在大量反射的情况下,可以提升型能20倍以上
				getM.setAccessible(true);
			}
			Object curVal = getM.invoke(vo);
			return curVal;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	
	private static <T>  Object getValTwo(T vo, String column) {
		try {
			if (vo == null) {
				return null;
			}
			Method getM =Common.getGetterMethod(vo.getClass(), column);
			if(getM.isAccessible()){
				//进行安全检查
				getM.setAccessible(false);
			}
			Object curVal = getM.invoke(vo);
			return curVal;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}